//
//  @ Project : Untitled
//  @ File Name : BundleImp.cpp
//  @ Date : 2009/8/31
//  @ Author : 
//
//
#include "FrameworkPublic.h"
#include "FrameworkListener.h"
#include "FrameworkImp.h"
#include "ServiceReferenceImp.h"
#include "ServiceRegistrationImp.h"
#include "BundleActivator.h"  //include this for some default class function implement
#include "BundleContextImp.h"
#include "BundleImp.h"

USING_NAME_SPACE_OSGI

int BundleImp::start(int options) 
{
	if( m_State==Bundle::UNINSTALLED )
		return -1;

	if( m_State==Bundle::ACTIVE )
		return 0;

	if( m_State!=Bundle::INSTALLED )
		return -2;

	m_State = Bundle::STARTING;
	BundleContextImp* contextImp = static_cast<BundleContextImp*>(m_Context);
	FrameworkImp* frameworkImp = static_cast<FrameworkImp*>(contextImp->getFramework());
	frameworkImp->fireBundleEvent( BundleEvent::LAZY_ACTIVATION, this );

	BundleActivator* m_ActivatorClass = (BundleActivator*)m_LoadClassFun( m_Activator.c_str() );
	if( m_ActivatorClass ) {
		m_ActivatorClass->start( m_Context );
	} else {
		m_State = Bundle::STOPING;
		frameworkImp->fireBundleEvent( BundleEvent::STOPPING, this );		
		m_State = Bundle::RESOLVED;
		frameworkImp->fireBundleEvent( BundleEvent::STOPPED, this );
	}

	m_State = Bundle::ACTIVE;
	frameworkImp->fireBundleEvent( BundleEvent::STARTED, this );
	return 0;
}

int BundleImp::stop(int options)
{
	if( m_State==Bundle::UNINSTALLED )
        return -1;

	if( m_State!=Bundle::STARTING && m_State!=Bundle::ACTIVE )
		return -2;

	BundleContextImp* contextImp = static_cast<BundleContextImp*>(m_Context);
	FrameworkImp* frameworkImp = static_cast<FrameworkImp*>(contextImp->getFramework());
	int prior = m_State;
	m_State = Bundle::STOPING;
	frameworkImp->fireBundleEvent( BundleEvent::STOPPING, this );
	if( prior==Bundle::ACTIVE && m_ActivatorClass ) {
		m_ActivatorClass->stop( m_Context );
	}
	m_State = Bundle::RESOLVED;
	frameworkImp->fireBundleEvent( BundleEvent::STOPPED, this );
	return 0;
}

int BundleImp::update()
{
	if( m_State==Bundle::UNINSTALLED )
		return -1;

	if( m_State==Bundle::ACTIVE || m_State==Bundle::STARTING || m_State==Bundle::STOPING ) {
		int stopped = stop( 0 );
		if( 0!=stopped )
			return stopped;
	}

	// install updated version.
	BundleContextImp* contextImp = static_cast<BundleContextImp*>(m_Context);
	FrameworkImp* frameworkImp = static_cast<FrameworkImp*>(contextImp->getFramework());
	int prior = m_State;
	m_State = Bundle::INSTALLED;
	frameworkImp->fireBundleEvent( BundleEvent::UPDATED, this );
	if( prior==Bundle::ACTIVE ) {
		if( 0!=start(0) ) 
			frameworkImp->fireFrameEvent( FrameworkEvent::ERRORED, this );
	}
	return 0;
}

void BundleImp::uninstall() 
{
	if( m_State==Bundle::UNINSTALLED )
		return;

	BundleContextImp* contextImp = static_cast<BundleContextImp*>(m_Context);
	FrameworkImp* frameworkImp = static_cast<FrameworkImp*>(contextImp->getFramework());
	if( m_State==Bundle::ACTIVE || m_State==Bundle::STARTING || m_State==Bundle::STOPING ) {
		if( 0!=stop(0) ) {
			frameworkImp->fireFrameEvent( FrameworkEvent::ERRORED, this );
		}
	}

	m_State = Bundle::UNINSTALLED;
	frameworkImp->fireBundleEvent( BundleEvent::UNINSTALLED, this );
}

bool BundleImp::resolve()
{
	if( m_BundleDll )
		return true;

	FrameworkImp* frame = static_cast<FrameworkImp*>( static_cast<BundleContextImp*>(m_Context)->getFramework());
	std::string strBundleLocation = frame->m_BoundleLocationBase;
	strBundleLocation += m_Location;
	m_BundleDll = LoadLibraryA( strBundleLocation.c_str() );
	if( m_BundleDll==0 )
		return 0;

	m_LoadClassFun = (ClassLoader)GetProcAddress( m_BundleDll, "ClassLoader" );
	return m_LoadClassFun!=0;
}

void* BundleImp::loadClass(const char* name) 
{
	// If this bundle is a fragment bundle then this method, only return directly.
	if( m_Fragment || m_State==Bundle::UNINSTALLED )
		return 0;

	if( m_State==Bundle::INSTALLED ) {
		if( !resolve() ) {
			BundleContextImp* contextImp = static_cast<BundleContextImp*>(m_Context);
			FrameworkImp* frameworkImp = static_cast<FrameworkImp*>(contextImp->getFramework());
			frameworkImp->fireFrameEvent( FrameworkEvent::ERRORED, this );
			return 0;
		}
	}

	return m_LoadClassFun ? m_LoadClassFun(name) : 0;
}